--- ========================================================= ---
---  Setup Revision, Version, Date and add to AceLibrary
--- ========================================================= ---
local VERSION = tonumber(("$Revision: 52946 $"):match("%d+"))

DaHud = AceLibrary("AceAddon-2.0"):new("AceDB-2.0", "AceEvent-2.0", "AceConsole-2.0", "AceModuleCore-2.0", "FuBarPlugin-2.0", "AceHook-2.1", "AceComm-2.0")
local DaHud, self = DaHud, DaHud
DaHud.version = "r" .. VERSION
DaHud.revision = VERSION
DaHud.date = ("$Date: 2007-10-23 02:00:18 -0400 (Tue, 23 Oct 2007) $"):match("%d%d%d%d%-%d%d%-%d%d")

--- ========================================================= ---
---  Setup Locals
--- ========================================================= ---
local Waterfall = AceLibrary:HasInstance("Waterfall-1.0") and AceLibrary("Waterfall-1.0")
local Dewdrop = AceLibrary("Dewdrop-2.0")
local DogTag = AceLibrary("DogTag-1.0")
local Media = AceLibrary("SharedMedia-1.0")

local localeTables = {}
function DaHud:L(name)
	if not localeTables[name] then
		localeTables[name] = setmetatable({}, {__index = function(self, key)
			self[key] = key
			return key
		end})
	end
	return localeTables[name]
end

local L = DaHud:L("DaHud")

DaHud_ConfigMode = false

--- ========================================================= ---
---  Setup FuBar Configuration
--- ========================================================= ---
DaHud.hasIcon = true
DaHud.hideWithoutStandby = true
DaHud.defaultPosition = "MINIMAP"
DaHud.defaultMinimapPosition = 250
DaHud.hasNoText = false
DaHud.hasNoColor = true
DaHud.cannotDetachTooltip = true
DaHud.independentProfile = true
DaHud.blizzardTooltip = true

--- ========================================================= ---
---  Setup Database
--- ========================================================= ---
DaHud:RegisterDB("DaHudDB")
do
DaHud:RegisterDefaults("profile", {
		Name = "Default",
		Revision = VERSION,
		settings = {
			locked = false,
			clamped = true,
			scale = 1.00,
			strata = "MEDIUM",
			animatespeed = 0.02,
			posx = 0,
			posy = 0,
			oocalpha = 0.50,
			combatalpha = 1,
			regenalpha = 0.75,
			targetalpha = 0.75,
		},
		colors = {
			health = {0, 1, 0, 1},
			mana = {0, 0.25, 1, 1},
			rage = {1, 0, 0, 1},
			energy = {1, 1, 0, 1},
			focus = {1, 1, 0, 1},
			none = {0, 0, 0, 1},
			custom = {1, 1, 1, 1},
			combat = {1, 0, 0, 1},
			experience = {0.75, 0, 0.75, 1},
			reputation = {0, 0.75, 0.75, 1},
			threat = {1, 0, 0, 1},
			spellcasting = {0, 1, 0, 1},
			spellchanneling = {0, 0.25, 1, 1},
			spellinterrupted = {1, 0, 0, 1},
			textshadow = {1, 1, 1, 1},
			barbg = {0.30, 0.30, 0.30, 0.75},
		},
})
end

--- ========================================================= ---
---  Setup Validates for Options
--- ========================================================= ---
local strataValidate = {
	BACKGROUND = L["Background"],
	LOW = L["Low"],
	MEDIUM = L["Medium"],
	HIGH = L["High"],
	DIALOG = L["Dialog"],
	TOOLTIP = L["Tooltip"],
}

local strataValidateDesc = {}

--- ========================================================= ---
---  Setup Options
--- ========================================================= ---
DaHud.options = {
	type = 'group',
	handler = DaHud,
	args = {
		appearance = {
			name = L["Appearance"],
			desc = L["Change how the DaHud Appearance looks in general."],
			type = 'group',
			args = {
				colors = {
					name = L["Colors"],
					desc = L["Change the Colors that the DaHud uses."],
					type = 'group',
					args = {
						healthColor = {
							name = L["Health Colors"],
							desc = L["Set what color your health color is."],
							type = 'group',
							pass = true,
							get = function(value)
								return unpack(self.db.profile.colors[value])
							end,
							set = "SetColor",
							args = {
								health = {
									name = L["Health"],
									desc = L["Color for your Health."],
									type = 'color',
									hasAlpha = false,
								},
							},
						},
						powerColor = {
							name = L["Power Colors"],
							desc = L["Set what color each power color is."],
							type = 'group',
							pass = true,
							get = function(value)
								return unpack(self.db.profile.colors[value])
							end,
							set = "SetColor",
							args = {
								mana = {
									name = L["Mana"],
									desc = L["Color for your Mana."],
									type = 'color',
									hasAlpha = false,
								},
								rage = {
									name = L["Rage"],
									desc = L["Color for your Rage."],
									type = 'color',
									hasAlpha = false,
								},
								energy = {
									name = L["Energy"],
									desc = L["Color for your Energy."],
									type = 'color',
									hasAlpha = false,
								},
								focus = {
									name = L["Focus"],
									desc = L["Color for your Focus."],
									type = 'color',
									hasAlpha = false,
								},
							},
						},
						otherColor = {
							name = L["Other Colors"],
							desc = L["Set what color you want these to be."],
							type = 'group',
							pass = true,
							get = function(value)
								return unpack(self.db.profile.colors[value])
							end,
							set = "SetColor",
							args = {
								none = {
									name = L["None"],
									desc = L["Color for None."],
									type = 'color',
									hasAlpha = false,
								},
								custom = {
									name = L["Custom"],
									desc = L["Color for Custom."],
									type = 'color',
									hasAlpha = false,
								},
								combat = {
									name = L["Combat"],
									desc = L["Color for when in Combat."],
									type = 'color',
									hasAlpha = false,
								},
								experience = {
									name = L["Experience"],
									desc = L["Color for your Experience."],
									type = 'color',
									hasAlpha = false,
								},
								reputation = {
									name = L["Reputation"],
									desc = L["Color for your Reputation."],
									type = 'color',
									hasAlpha = false,
								},
								threat = {
									name = L["Threat"],
									desc = L["Color for your Threat."],
									type = 'color',
									hasAlpha = false,
								},
							},
						},
						spellColor = {
							name = L["Spell Colors"],
							desc = L["Set what color you want these to be."],
							type = 'group',
							pass = true,
							get = function(value)
								return unpack(self.db.profile.colors[value])
							end,
							set = "SetColor",
							args = {
								spellcasting = {
									name = L["Casting"],
									desc = L["Color for Casting."],
									type = 'color',
									hasAlpha = false,
								},
								spellchanneling = {
									name = L["Channeling"],
									desc = L["Color for Channeling."],
									type = 'color',
									hasAlpha = false,
								},
								spellinterrupted = {
									name = L["Interrupted"],
									desc = L["Color for when Interrupted."],
									type = 'color',
									hasAlpha = false,
								},
							},
						},
						textColor = {
							name = L["Text Colors"],
							desc = L["Set what color you want these to be."],
							type = 'group',
							pass = true,
							get = function(value)
								return unpack(self.db.profile.colors[value])
							end,
							set = "SetColor",
							args = {
								textshadow = {
									name = L["Text Shadow Color"],
									desc = L["Color for Text Shadows."],
									type = 'color',
									hasAlpha = false,
								},
							},
						},
						barColor = {
							name = L["Statusbars Colors"],
							desc = L["Set what color you want these to be."],
							type = 'group',
							pass = true,
							get = function(value)
								return unpack(self.db.profile.colors[value])
							end,
							set = "SetColor",
							args = {
								barbg = {
									name = L["Bar Background Color"],
									desc = L["Color for Bar Background."],
									type = 'color',
									hasAlpha = true,
								},
							},
						},
					},
				},
				alphas = {
					name = L["Alpha's"],
					desc = L["Change the Alpha's based on certain events."],
					type = 'group',
					args = {
						oocalpha = {
							name = L["Out of Combat"],
							desc = L["Set the Out of Combat Alpha."],
							type = 'range',
							min = 0,
							max = 1,
							step = 0.05,
							bigStep = 0.1,
							get = function()
								return self.db.profile.settings.oocalpha
							end,
							set = function(value)
								self.db.profile.settings.oocalpha = value
								self:ProcessAlpha()
							end,
						},
						combatalpha = {
							name = L["In Combat"],
							desc = L["Set the In Combat Alpha."],
							type = 'range',
							min = 0,
							max = 1,
							step = 0.05,
							bigStep = 0.1,
							get = function()
								return self.db.profile.settings.combatalpha
							end,
							set = function(value)
								self.db.profile.settings.combatalpha = value
								self:ProcessAlpha()
							end,
						},
						regenalpha = {
							name = L["Health Regen Combat"],
							desc = L["Set the Health Regen Alpha."],
							type = 'range',
							min = 0,
							max = 1,
							step = 0.05,
							bigStep = 0.1,
							get = function()
								return self.db.profile.settings.regenalpha
							end,
							set = function(value)
								self.db.profile.settings.regenalpha = value
								self:ProcessAlpha()
							end,
						},
						targetalpha = {
							name = L["Target"],
							desc = L["Set the Target Alpha."],
							type = 'range',
							min = 0,
							max = 1,
							step = 0.05,
							bigStep = 0.1,
							get = function()
								return self.db.profile.settings.targetalpha
							end,
							set = function(value)
								self.db.profile.settings.targetalpha = value
								self:ProcessAlpha()
							end,
						},
					},
				},
				scale = {
					name = L["Scale"],
					desc = L["Set the general Scale of the DaHud."],
					type = 'range',
					min = 0.25,
					max = 3,
					step = 0.01,
					bigStep = 0.05,
					get = function()
						return self.db.profile.settings.scale
					end,
					set = "SetScale"
				},
				strata = {
					name = L["Frame Strata"],
					desc = L["Choose the layer the unit frames are located on."],
					type = 'text',
					validate = strataValidate,
					validateDesc = strataValidateDesc,
					get = function()
						return self.db.profile.settings.strata
					end,
					set = "SetFrameStrata",
				},
				animatespeed = {
					name = L["Animate Speed"],
					desc = L["Set the Animate Speed on the Bars (glide)."],
					type = 'range',
					min = 0.01,
					max = 1,
					step = 0.01,
					bigStep = 0.10,
					get = function()
						return self.db.profile.settings.animatespeed
					end,
					set = "SetAnimateSpeed"
				},
				posx = {
					name = L["Pos X"],
					desc = L["Change the X Position."],
					type = 'range',
					min = -500,
					max = 500,
					step = 1,
					bigStep = 20,
					get = function()
						return self.db.profile.settings.posx
					end,
					set = function(value) 
						self:SetFramePos("posx", value)
					end,
				},
				posy = {
					name = L["Pos Y"],
					desc = L["Change the Y Position."],
					type = 'range',
					min = -500,
					max = 500,
					step = 1,
					bigStep = 20,
					get = function()
						return self.db.profile.settings.posy
					end,
					set = function(value) 
						self:SetFramePos("posy", value)
					end,
				},
			},
		},
		settings = {
			name = L["Settings"],
			desc = L["Change the Settings."],
			type = 'group',
			args = {
				config = {
					name = L["Config Mode"],
					desc = L["Set DaHud into Config Mode."],
					type = 'toggle',
					order = 1000,
					get = function()
						return DaHud_ConfigMode
					end,
					set = function()
						DaHud_ConfigMode = not(DaHud_ConfigMode)
						self:SetConfigMode()
					end,
				},
			},
		},	
	}
}

--- ========================================================= ---
---  Setup Menu Request and Tooltip
--- ========================================================= ---
DaHud.OnMenuRequest = DaHud.options

function DaHud:OnTooltipUpdate()
	GameTooltip:AddLine("DaHud")
	GameTooltip:AddLine(" ")
	GameTooltip:AddDoubleLine(LOCKED .. ":", (self.db.profile.settings.locked and YES or NO), 1, 1, 0, 1, 1, 1)
	GameTooltip:AddLine(" ")
	GameTooltip:AddLine(L["|cffffff00Shift-Click|r to lock/unlock DaHud"], 0.2, 1, 0.2)
	if Waterfall then
		GameTooltip:AddLine(L["|cffffff00Left-Click|r to change settings with a nice GUI configuration."], 0.2, 1, 0.2)
	end
	GameTooltip:AddLine(L["|cffffff00Right-Click|r to change settings with a drop-down menu."], 0.2, 1, 0.2)
end

--- ========================================================= ---
---  Setup Waterfall
--- ========================================================= ---
if Waterfall then
	Waterfall:Register("DaHud", 
						"aceOptions", DaHud.options,
						"title", L["DaHud Configuration"],
						"treeLevels", 5);
end

--- ========================================================= ---
---  Setup Modules
--- ========================================================= ---

local modulesWithFunction = setmetatable({}, {__index = function(self, key)
	local t = {}
	for name, module in DaHud:IterateModules() do
		if type(module[key]) == "function" and DaHud:IsModuleActive(module) then
			t[#t+1] = module
		end
	end
	self[key] = t
	
	return t
end})

function DaHud:OnModuleCreated(name, module)
	for k in pairs(modulesWithFunction) do
		modulesWithFunction[k] = nil
	end
end

function DaHud.modulePrototype:RegisterDaHudOption(data)
	local args = DaHud.options.args
	local name = self.name
	if args[name] then
		local i = 1
		while args[name .. i] do
			i = i + 1
		end
		name = name .. i
	end
	args[name] = data
	if not data.handler then
		data.handler = self
	end
	if data.args then
		data.args.active = {
			type = 'toggle',
			name = L["Enable"],
			desc = L["Enable this module"],
			get = "IsModuleActive",
			set = "ToggleModuleActive",
			handler = DaHud,
			passValue = self,
		}
	end
end

--- ========================================================= ---
---  On Intitalize
--- ========================================================= ---
function DaHud:OnInitialize()
	self:RegisterChatCommand('/DaHud', {
		type = 'execute',
		func = function()
			self:OpenMenu()
		end
	})
	
	for k,v in pairs(self.db.profile) do
		for name, module in self:IterateModules() do
			if module.db then
				local db = module.db.profile
				if rawget(db, k) then
					db[k] = v
					self.db.profile[k] = nil
					break
				end
			end
		end
	end
	
	self:CreateFrames()
end

--- ========================================================= ---
---  On Enable
--- ========================================================= ---
function DaHud:OnEnable()
	self:CreateFrames()
	self:SetScale()
	self:SetFrameStrata()
	self:SetFramePos()
	self:ProcessAlpha()
	
	self:RegisterEvent("AceDB20_ResetDB")
	
	self:RegisterEvent("DaHud_ReloadAllFrames")	
	
	self:RegisterEvent("PLAYER_REGEN_ENABLED")
	self:RegisterEvent("PLAYER_REGEN_DISABLED")
	self:RegisterEvent("PLAYER_TARGET_CHANGED")
	self:RegisterEvent("UNIT_HEALTH")
end

--- ========================================================= ---
---  On Disable
--- ========================================================= ---
function DaHud:OnDisable()

end

--- ========================================================= ---
---  On Module Enable
--- ========================================================= ---
function DaHud:OnModuleEnable()
	for k in pairs(modulesWithFunction) do
		modulesWithFunction[k] = nil
	end
end

--- ========================================================= ---
---  On Module Disable
--- ========================================================= ---
function DaHud:OnModuleDisable()
	for k in pairs(modulesWithFunction) do
		modulesWithFunction[k] = nil
	end
end

--- ========================================================= ---
---  AceDB20_ResetDB
--- ========================================================= ---
function DaHud:AceDB20_ResetDB()
	self:TriggerEvent("DaHud_ReloadAllFrames")
end

--- ========================================================= ---
---  DaHud_ReloadAllFrames
--- ========================================================= ---
function DaHud:DaHud_ReloadAllFrames()
	self:SetScale()
	self:SetFrameStrata()
	self:SetFramePos()
	self:ProcessAlpha()
end

--- ========================================================= ---
--- PLAYER_REGEN_ENABLED
--- ========================================================= ---
function DaHud:PLAYER_REGEN_ENABLED()
	getglobal("DaHudFrame"):SetAlpha(self.db.profile.settings.oocalpha)
end

--- ========================================================= ---
---  PLAYER_REGEN_DISABLED
--- ========================================================= ---
function DaHud:PLAYER_REGEN_DISABLED()
	getglobal("DaHudFrame"):SetAlpha(self.db.profile.settings.combatalpha)
	
	if DaHud_ConfigMode then
		DEFAULT_CHAT_FRAME:AddMessage("DaHud Config Mode Turned Off Because In Combat!")
		DaHud_ConfigMode = false
		self:SetConfigMode()
	end
end

--- ========================================================= ---
--- PLAYER_TARGET_CHANGED
--- ========================================================= ---
function DaHud:PLAYER_TARGET_CHANGED()
	self:ProcessAlpha()
end

--- ========================================================= ---
---  UNIT_HEALTH
--- ========================================================= ---
function DaHud:UNIT_HEALTH()
	if arg1 == "player" then
		self:ProcessAlpha()
	end
end

--- ========================================================= ---
---  On Click
--- ========================================================= ---
function DaHud:OnClick()
	local shift, alt, ctrl = IsShiftKeyDown(), IsAltKeyDown(), IsControlKeyDown()
	if shift and not alt and not ctrl then
		self.db.profile.settings.locked = not self.db.profile.settings.locked
		self:UpdateTooltip()
	else	
		if Waterfall then
			Waterfall:Open("DaHud")
		else
			self:Print(L["Waterfall-1.0 is required to access the GUI."])
		end
	end
end

--- ========================================================= ---
---  Set Color
--- ========================================================= ---
function DaHud:SetColor(given_kind, r, g, b, a)
	local kind = given_kind
	local colors = self.db.profile.colors[kind]
	
	if r then
		colors[1] = r
		colors[2] = g
		colors[3] = b
		if a then
			colors[4] = a
		end
	else
		r, g, b, a = unpack(colors)
	end
	
	if kind == "textshadow" then
		DaHud_Module_Text:UpdateAllFrames()
	elseif kind == "barbg" then
		DaHud_Module_Bars:UpdateAllFrames()
	end
end

--- ========================================================= ---
---  Set Scale
--- ========================================================= ---
function DaHud:SetScale(value)
	if value then
		self.db.profile.settings.scale = value
	else
		value = self.db.profile.settings.scale
	end
	
	DaHudFrame:SetScale(value)
end

--- ========================================================= ---
---  Set Frame Strata
--- ========================================================= ---
function DaHud:SetFrameStrata(value)
	if value then
		self.db.profile.settings.strata = value
	else
		value = self.db.profile.settings.strata
	end
	
	DaHudFrame:SetFrameStrata(value)
end

--- ========================================================= ---
---  Set Animate Speed
--- ========================================================= ---
function DaHud:SetAnimateSpeed(value)
	if value then
		self.db.profile.settings.animatespeed = value
	else
		value = self.db.profile.settings.animatespeed
	end
end

--- ========================================================= ---
---  Set Frame Pos
--- ========================================================= ---
function DaHud:SetFramePos(val, value)
	local posx, posy
	if not(val) then
		posx = self.db.profile.settings.posx
		posy = self.db.profile.settings.posy
	elseif val == "posx" then
		if not value then return end
		self.db.profile.settings.posx = value
		posx = self.db.profile.settings.posx
		posy = self.db.profile.settings.posy
	elseif val == "posy" then
		if not value then return end
		self.db.profile.settings.posy = value
		posx = self.db.profile.settings.posx
		posy = self.db.profile.settings.posy
	end
	
	DaHudFrame:SetPoint("Center", WorldFrame, "Center", posx, posy)
end

--- ========================================================= ---
---  Format Time
--- ========================================================= ---
function DaHud:FormatTime(time)
	if(time > 60 or self.TimerSet) then
		local minutes = math.floor((time / 60));
		local seconds = math.ceil(time - (60 * minutes));
		if (seconds == 60) then
			minutes = minutes + 1;
			seconds = 0;
		end
		if(strlen(seconds) < 2) then
			seconds =  "0"..seconds;
		end
		self.TimerSet = 1;
		return format("%s:%s", minutes, seconds);
	else
		return string.format( "%.1f", time);
	end
end

--- ========================================================= ---
---  Create Frame
--- ========================================================= ---
function DaHud:CreateFrame(type, name, parent, size, point, strata)
	local f
	if type == "Button" then
		f = CreateFrame(type, name, parent, "SecureUnitButtonTemplate")
	else
		f = CreateFrame(type, name, parent)
	end
	local width, height = unpack(size)

	f:SetWidth(width)
	f:SetHeight(height)
	f:SetPoint(unpack(point))

	if(strata) then
		f:SetFrameStrata(strata)
	end
	
	if type == "Button" then
		f:RegisterForClicks("AnyUp")
		f:EnableMouse(true)
		f:SetScript("OnEnter", function(self)
			if self.tt == "always" or (self.tt == "ooc" and not(InCombatLockdown())) then
				GameTooltip:SetOwner(self, "ANCHOR_NONE")
				GameTooltip:SetPoint("BOTTOM", self, "TOP", 0, 20)
				GameTooltip:SetUnit("player")
				GameTooltip:Show()
			end
		end)
		
		f:SetScript("OnLeave", function(self) 
			if(GameTooltip:IsOwned(self)) then
				GameTooltip:Hide()
			end
		end)
	end

	f:Show()

	return f
end

--- ========================================================= ---
---  Process Frames
--- ========================================================= ---
function DaHud:CreateFrames()
	local main = DaHud:CreateFrame("Frame", "DaHudFrame", UIParent, {50, 50}, {"CENTER", WorldFrame, "CENTER"}, "LOW")
end

--- ========================================================= ---
---  Process Alpha
--- ========================================================= ---
function DaHud:ProcessAlpha()
	if DaHud_ConfigMode then return end
	local name, realm = UnitName("target")
	if InCombatLockdown() then
		getglobal("DaHudFrame"):SetAlpha(self.db.profile.settings.combatalpha)
	elseif name then
		getglobal("DaHudFrame"):SetAlpha(self.db.profile.settings.targetalpha)
	else
		local health = tonumber(DogTag:Evaluate("player", "[PercentHP]"))
		if health and health < 100 then
			getglobal("DaHudFrame"):SetAlpha(self.db.profile.settings.regenalpha)
		else
			getglobal("DaHudFrame"):SetAlpha(self.db.profile.settings.oocalpha)
		end
	end
end

--- ========================================================= ---
---  Set Config Mode
--- ========================================================= ---
function DaHud:SetConfigMode()
	self:TriggerEvent("DaHud_SetConfigMode")
	
	if DaHud_ConfigMode then
		getglobal("DaHudFrame"):SetAlpha(1)
	else
		self:ProcessAlpha()
	end
end